package org.shiro.demo.controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.shiro.demo.dao.util.QueryCondition;
import org.shiro.demo.entity.Order;
import org.shiro.demo.entity.Pay2Manager;
import org.shiro.demo.entity.ResponseResult;
import org.shiro.demo.entity.Ticket;
import org.shiro.demo.entity.User;
import org.shiro.demo.entity.WeixinAccount;
import org.shiro.demo.service.IBaseService;
import org.shiro.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.utils.CommonUtil;
import com.utils.GetWxOrderno;
import com.utils.RequestHandler;
import com.utils.Sha1Util;
import com.utils.TenpayUtil;

/**
 * 微信 公共账号V3。
 * 
 * 公众号 专用
 * 
 * @author Chinesejie
 *
 */
@Controller
public class V3Controller {
	@Value("#{configProperties['v3PayNotifyUrl']}")
	private String v3PayNotifyUrl;
	@Resource(name = "baseService")
	private IBaseService baseService;
	@Resource
	private IUserService userService;

	private User getCurrentUser() {
		// 设置订单主人为当前登陆的用户.
		Subject currentUser = SecurityUtils.getSubject();

		return (User) currentUser.getPrincipal();
	}

	@RequestMapping(value = "/mainServlet")
	@RequiresAuthentication
	@RequiresRoles("customer")
	public String mainServlet(HttpSession session, javax.servlet.http.HttpServletRequest request) {
		// 得到关键信息...匹配uuid 是否属于这个 用户
		User user = getCurrentUser();
		String uuid = request.getParameter("uuid");
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		queryConditions.add(new QueryCondition("uuid", QueryCondition.EQ, uuid));
		if (uuid.startsWith("o")) {
			Order order = (Order) baseService.getSingleResult(Order.class, queryConditions);
			if (order.getOrderProp().getId() != 1L || order.getUser().getId() != user.getId()) {// 未付款
				System.out.println("该订单不属于未支付状态或者 该订单不属于用户");
				return "redirect:/html/error.jsp";
			}
		}
		else{
			Ticket ticket = (Ticket) baseService.getSingleResult(Ticket.class, queryConditions);
			if (ticket.getOrderProp().getId() != 1L || ticket.getUser().getId() != user.getId()) {// 未付款
				System.out.println("该订单不属于未支付状态或者 该订单不属于用户");
				return "redirect:/html/error.jsp";
			}
		}
	
		// 共账号及商户相关参数
		String appid = "wx1d8e9a967a8c62bd";
		// String backUri = "http://pay.dxyxx.com/weixin2/topayServlet";
		String backUri = "https://rs88881234.com/chinesejie/topayServlet";
		// 授权后要跳转的链接所需的参数一般有会员号，金额，订单号之类，
		// 最好自己带上一个加密字符串将金额加上一个自定义的key用MD5签名或者自己写的签名,
		// 比如 Sign = %3D%2F%CS%userId
		String orderNo = appid + Sha1Util.getTimeStamp();
		// 传递 过去的money 不可靠
		backUri = backUri + "?userId=" + user.getId() + "&orderNo=" + uuid + "&describe=test&money=1780.00";
		// URLEncoder.encode 后可以在backUri 的url里面获取传递的所有参数
		backUri = URLEncoder.encode(backUri);
		// scope 参数视各自需求而定，这里用scope=snsapi_base
		// 不弹出授权页面直接授权目的只获取统一支付接口的openid...|||scope=snsapi_userinfo 可以获取用户的 信息
		// snsapi_base
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=" + appid + "&redirect_uri=" + backUri + "&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
		return "redirect:" + url;
	}

	/**
	 * 可能会超时，，那么 微信会重发。。 警惕警惕
	 * 
	 * @param session
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/topayServlet")
	@RequiresAuthentication
	@RequiresRoles("customer")
	public String topayServlet(HttpSession session, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) {

		// 网页授权后获取传递的参数
		String userId = request.getParameter("userId");
		String orderNo = request.getParameter("orderNo");
		String money = request.getParameter("money");
		String code = request.getParameter("code");
		// 金额 还是要自己来查的。
		double sessionMoney;
		List<QueryCondition> queryConditions2 = new ArrayList<QueryCondition>();
		queryConditions2.add(new QueryCondition("uuid", QueryCondition.EQ, orderNo));
		if (orderNo.startsWith("o")) {
			Order order = (Order) baseService.getSingleResult(Order.class, queryConditions2);
			sessionMoney = order.getMoney();
		} else {
			Ticket ticket = (Ticket) baseService.getSingleResult(Ticket.class, queryConditions2);
			sessionMoney = ticket.getMoney()*ticket.getDiscount();
		}
		// 金额转化为分为单位
		String finalmoney = String.format("%.2f", sessionMoney);
		finalmoney = finalmoney.replace(".", "");//变成分

		// 商户相关资料
		String appid = "wx1d8e9a967a8c62bd";
		String appsecret = "c687ad8537af8d8e1ca2fc573095a426";
		String partner = "1227994702";
		String partnerkey = "BdplgSwZUTqFBXdCikJB91kx6aCiIF3O";

		String openId = "";
		String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=authorization_code";

		JSONObject jsonObject = CommonUtil.httpsRequest(URL, "GET", null);
		if (null != jsonObject) {
			openId = jsonObject.getString("openid");
		}

		// 获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder
		String currTime = TenpayUtil.getCurrTime();
		// 8位日期
		String strTime = currTime.substring(8, currTime.length());
		// 四位随机数
		String strRandom = TenpayUtil.buildRandom(4) + "";
		// 10位序列号,可以自行调整。
		String strReq = strTime + strRandom;

		// 商户号
		String mch_id = partner;
		// 子商户号 非必输
		// String sub_mch_id="";
		// 设备号 非必输
		String device_info = "";
		// 随机数
		String nonce_str = strReq;
		// 商品描述
		// String body = describe;

		// 商品描述根据情况修改
		String body = "大象与猩猩电子购物";
		// 附加数据
		String attach = userId;
		// 商户订单号
		String out_trade_no = orderNo;
		int intMoney = Integer.parseInt(finalmoney);

		// 总金额以分为单位，不带小数点
		int total_fee = intMoney;
		// 订单生成的机器 IP
		String spbill_create_ip = request.getRemoteAddr();
		// 订 单 生 成 时 间 非必输
		// String time_start ="";
		// 订单失效时间 非必输
		// String time_expire = "";
		// 商品标记 非必输
		// String goods_tag = "";

		// 这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
		// String notify_url = "http://dxyxx.com/weixin2/notifyServlet";
		String notify_url = v3PayNotifyUrl;// 这个接口可以随意设置

		String trade_type = "JSAPI";
		String openid = openId;
		// 非必输
		// String product_id = "";
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", appid);
		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("attach", attach);
		packageParams.put("out_trade_no", out_trade_no);

		// 这里写的金额为1 分到时修改
//		packageParams.put("total_fee", "1");
		 packageParams.put("total_fee", total_fee+"");
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);

		packageParams.put("trade_type", trade_type);
		packageParams.put("openid", openid);

		RequestHandler reqHandler = new RequestHandler(request, response);
		reqHandler.init(appid, appsecret, partnerkey);

		String sign = reqHandler.createSign(packageParams);
		String xml = "<xml>" + "<appid>" + appid + "</appid>" + "<mch_id>" + mch_id + "</mch_id>" + "<nonce_str>" + nonce_str + "</nonce_str>" + "<sign>" + sign + "</sign>" + "<body><![CDATA[" + body + "]]></body>" + "<attach>" + attach + "</attach>" + "<out_trade_no>" + out_trade_no + "</out_trade_no>" +
		// 金额，这里写的1 分到时修改
				"<total_fee>" + total_fee + "</total_fee>" +
				// "<total_fee>"+finalmoney+"</total_fee>"+
				"<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" + "<notify_url>" + notify_url + "</notify_url>" + "<trade_type>" + trade_type + "</trade_type>" + "<openid>" + openid + "</openid>" + "</xml>";
		// System.out.println(xml);
		String allParameters = "";
		try {
			allParameters = reqHandler.genPackage(packageParams);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		String prepay_id = "";
		try {
			prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);//
			if (prepay_id.equals("")) {
				request.setAttribute("ErrorMsg", "统一支付接口获取预支付订单出错");
				return "redirect:html/error.jsp";
			}
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		SortedMap<String, String> finalpackage = new TreeMap<String, String>();
		String appid2 = appid;
		String timestamp = Sha1Util.getTimeStamp();
		String nonceStr2 = nonce_str;
		String prepay_id2 = "prepay_id=" + prepay_id;
		String packages = prepay_id2;
		finalpackage.put("appId", appid2);
		finalpackage.put("timeStamp", timestamp);
		finalpackage.put("nonceStr", nonceStr2);
		finalpackage.put("package", packages);
		finalpackage.put("signType", "MD5");
		String finalsign = reqHandler.createSign(finalpackage);
		System.out.println("html/pay.html?appid=" + appid2 + "&timeStamp=" + timestamp + "&nonceStr=" + nonceStr2 + "&package=" + packages + "&sign=" + finalsign);
		return "redirect:" + "html/pay.html?appid=" + appid2 + "&timeStamp=" + timestamp + "&nonceStr=" + nonceStr2 + "&package1=" + URLEncoder.encode(packages) + "&sign=" + finalsign + "&uuid=" + orderNo;

	}

	@RequestMapping(value = "/notifyServlet")
	public void notifyServlet(HttpSession session, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
			String line = null;
			StringBuilder sb = new StringBuilder();
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			System.out.println("----微信返回");
			System.out.println(sb);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// ----店长来取钱咯-------------------------------------------------------------------------------------------------------------------
	@RequestMapping(value = "/getpay")
	public String getpay(HttpSession session, javax.servlet.http.HttpServletRequest request) {
		ResponseResult rr = new ResponseResult();
		// 传入一个pay id
		String id = request.getParameter("id");

		Pay2Manager moneyPay = (Pay2Manager) baseService.getById(Pay2Manager.class, id);
		if (moneyPay == null) {
			rr.setCode(0);
			rr.setInfo("支付订单不存在  ");
			return "redirect:/html/error.jsp";
		}
		if (moneyPay.isAtmed()) {
			rr.setCode(0);
			rr.setInfo("订单已经支付");
			return "redirect:/html/error.jsp";
		}

		// 共账号及商户相关参数
		String appid = "wx1d8e9a967a8c62bd";
		// String backUri = "http://pay.dxyxx.com/weixin2/topayServlet";
		String backUri = "https://rs88881234.com/chinesejie/fkServlet";
		// 授权后要跳转的链接所需的参数一般有会员号，金额，订单号之类，
		// 最好自己带上一个加密字符串将金额加上一个自定义的key用MD5签名或者自己写的签名,
		// 比如 Sign = %3D%2F%CS%
		String orderNo = appid + Sha1Util.getTimeStamp();
		backUri = backUri + "?userId= " + moneyPay.getPayee() + "&orderNo=" + id + "&describe=test&money=" + moneyPay.getMoney();
		// URLEncoder.encode 后可以在backUri 的url里面获取传递的所有参数
		backUri = URLEncoder.encode(backUri);
		// scope 参数视各自需求而定，这里用scope=snsapi_base
		// 不弹出授权页面直接授权目的只获取统一支付接口的openid
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + "appid=" + appid + "&redirect_uri=" + backUri + "&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect";
		rr.setCode(1);
		rr.setInfo("赶紧领钱去");
		rr.setObject(url);
		return "redirect:" + url;
	}

	private static DefaultResourceLoader loader = new DefaultResourceLoader();

	@RequestMapping(value = "/fkServlet")
	public String fkServlet(HttpSession session, javax.servlet.http.HttpServletRequest request, HttpServletResponse response) {
		// 网页授权后获取传递的参数
		String userId = request.getParameter("userId");
		String orderNo = request.getParameter("orderNo");
		String money = request.getParameter("money");
		String code = request.getParameter("code");
		// 判断 oderNo跟userId跟 money 对不对
		Pay2Manager pay2Manager = baseService.getById(Pay2Manager.class, orderNo);
		if (pay2Manager == null || !pay2Manager.getPayee().equals(userId)) {
			System.out.println("信息有误");
			return "redirect:html/error.jsp";
		}
		WeixinAccount waccount = baseService.getById(WeixinAccount.class, userId);// phone
																					// 是主键
		// 金额转化为分为单位
		float sessionmoney = Float.parseFloat(money);
		String finalmoney = String.format("%.2f", sessionmoney);
		finalmoney = finalmoney.replace(".", "");

		// 商户相关资料
		String appid = "wx1d8e9a967a8c62bd";

		String appsecret = "c687ad8537af8d8e1ca2fc573095a426";
		String partner = "1227994702";
		String partnerkey = "BdplgSwZUTqFBXdCikJB91kx6aCiIF3O";
		String openId = "";
		String URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=authorization_code";

		JSONObject jsonObject = CommonUtil.httpsRequest(URL, "GET", null);
		if (null != jsonObject) {
			openId = jsonObject.getString("openid");
		}
		// 判断 openid 是否等于 useid 绑定的 openid
		if (!waccount.getOpenid().equals(openId)) {
			System.out.println("微信号不对应");
			return "redirect:html/error.jsp";
		}
		// 获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder
		String currTime = TenpayUtil.getCurrTime();
		// 8位日期
		String strTime = currTime.substring(8, currTime.length());
		// 四位随机数
		String strRandom = TenpayUtil.buildRandom(4) + "";
		// 10位序列号,可以自行调整。
		String strReq = strTime + strRandom;

		// 商户号
		String mch_id = partner;
		// 子商户号 非必输
		// String sub_mch_id="";
		// 设备号 非必输
		String device_info = "";
		// 随机数
		String nonce_str = strReq;
		// 商品描述
		// String body = describe;

		// 商品描述根据情况修改
		String body = "美食";
		// 附加数据
		String attach = userId;
		// 商户订单号
		String out_trade_no = orderNo;
		int intMoney = Integer.parseInt(finalmoney);

		// 总金额以分为单位，不带小数点
		int total_fee = intMoney;
		// 订单生成的机器 IP
		String spbill_create_ip = request.getRemoteAddr();
		// 订 单 生 成 时 间 非必输
		// String time_start ="";
		// 订单失效时间 非必输
		// String time_expire = "";
		// 商品标记 非必输
		// String goods_tag = "";

		// 这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
		// String notify_url = "http://pay.xywsc.com/weixin3/notifyServlet";

		// String trade_type = "JSAPI";
		String openid = openId;
		// 非必输
		// String product_id = "";
		String desc = "refund";
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("mch_appid", appid);
		packageParams.put("mchid", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("partner_trade_no", out_trade_no);
		packageParams.put("check_name", "NO_CHECK");
		packageParams.put("desc", desc);

		// 这里写的金额为1 分到时修改 TODO
		packageParams.put("amount", "1");
		// packageParams.put("total_fee", "finalmoney");
		packageParams.put("spbill_create_ip", spbill_create_ip);

		packageParams.put("openid", openid);

		RequestHandler reqHandler = new RequestHandler(request, response);
		reqHandler.init(appid, appsecret, partnerkey);

		String sign = reqHandler.createSign(packageParams);
		String xml = "<xml>" + "<mch_appid>" + appid + "</mch_appid>" + "<mchid>" + mch_id + "</mchid>" + "<nonce_str>" + nonce_str + "</nonce_str>" + "<sign>" + sign + "</sign>" + "<partner_trade_no>" + out_trade_no + "</partner_trade_no>" +
		// 金额，这里写的1 分到时修改
				"<check_name>" + "NO_CHECK" + "</check_name>" + "<amount>" + 1 + "</amount>" +
				// "<total_fee>"+finalmoney+"</total_fee>"+
				"<desc>" + desc + "</desc>" + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" + "<openid>" + openid + "</openid>" + "</xml>";
		System.out.println(xml);

		// HttpGet httpget = new
		// HttpGet("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
		HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
		CloseableHttpClient httpclient = null;
		try {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			// FileInputStream instream = new FileInputStream(new
			// File("/home/user/tomcat8082/webapps/parttime/WEB-INF/classes/apiclient_cert.p12"));
			InputStream instream = loader.getResource("classpath:apiclient_cert.p12").getInputStream();

			try {
				keyStore.load(instream, "1226789102".toCharArray());
			} finally {
				instream.close();
			}

			// Trust own CA and all self-signed certs
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "1226789102".toCharArray()).build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

			httppost.setEntity(new StringEntity(xml));
			System.out.println("executing request" + httppost.getRequestLine());

			CloseableHttpResponse response1 = httpclient.execute(httppost);
			try {
				HttpEntity entity = response1.getEntity();

				System.out.println("----------------------------------------");
				System.out.println(response1.getStatusLine());
				if (entity != null) {
					// 处理
					System.out.println("Response content length: " + entity.getContentLength());
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
					String text;
					while ((text = bufferedReader.readLine()) != null) {
						System.out.println(text);
					}

				}
				EntityUtils.consume(entity);
			} finally {
				response1.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			return "redirect:html/error.jsp";

		} finally {
			try {
				httpclient.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		String url = "html/getsuccess.html?uuid=" + orderNo + "&money=" + money;
		return "redirect:" + url;
	}
	// ----店长来取钱咯ends-------------------------------------------------------------------------------------------------------------------

}
/**
 * 微信公众号支付，比微信app支付多了一个字段<attach><![CDATA[5350]]></attach>
 * 
 * <xml>
 * 
 * <appid><![CDATA[wx1d8e9a967a8c62bd]]></appid>
 * 
 * <attach><![CDATA[5350]]></attach>
 * 
 * <bank_type><![CDATA[CFT]]></bank_type>
 * 
 * <cash_fee><![CDATA[1]]></cash_fee>
 * 
 * <fee_type><![CDATA[CNY]]></fee_type>
 * 
 * <is_subscribe><![CDATA[Y]]></is_subscribe>
 * 
 * <mch_id><![CDATA[1227994702]]></mch_id>
 * 
 * <nonce_str><![CDATA[2109023190]]></nonce_str>
 * 
 * <openid><![CDATA[odsD7jvx8-8yrNy8uqBqpUguW-Cc]]></openid>
 * 
 * <out_trade_no><![CDATA[UasCtwwT5350]]></out_trade_no>
 * 
 * <result_code><![CDATA[SUCCESS]]></result_code>
 * 
 * <return_code><![CDATA[SUCCESS]]></return_code>
 * 
 * <sign><![CDATA[B5561F392B01D81A1070DAB03F03E968]]></sign>
 * 
 * <time_end><![CDATA[20150427210921]]></time_end>
 * 
 * <total_fee>1</total_fee>
 * 
 * <trade_type><![CDATA[JSAPI]]></trade_type>
 * 
 * <transaction_id><![CDATA[1000090237201504270093816604]]></transaction_id>
 * 
 * </xml>
 */
